package com.upstairstechnology.oi.notification.console;

import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.upstairstechnology.oi.determination.IntegrationCheck;
import com.upstairstechnology.oi.determination.OutstandingIntegration;
import com.upstairstechnology.oi.determination.OutstandingIntegration.File;

/**
 * Notification to the console (std out).
 * 
 * @author Jeff Jensen
 */
public class NotificationStrategyConsoleDefault implements
        NotificationStrategyConsole {
    /** Initial size of the StringBuilder for the message. */
    private static final int MESSAGE_INITIAL_CAPACITY = 4000;

    /** Logger instance. */
    private static final Logger LOGGER =
            LoggerFactory.getLogger(NotificationStrategyConsoleDefault.class);

    /** First indent level of output text. */
    private static final String INDENT_1 = "  ";

    /** Second indent level of output text. */
    private static final String INDENT_2 = INDENT_1 + INDENT_1;

    /** Third indent level of output text. */
    private static final String INDENT_3 = INDENT_1 + INDENT_2;

    /** Fourth indent level of output text. */
    private static final String INDENT_4 = INDENT_1 + INDENT_3;

    /**
     * {@inheritDoc}
     */
    public void notify(Set<OutstandingIntegration> oiSet) {
        StringBuilder sb = new StringBuilder(MESSAGE_INITIAL_CAPACITY);

        Iterator<OutstandingIntegration> i = oiSet.iterator();
        while (i.hasNext()) {
            OutstandingIntegration oi = i.next();
            String userId = oi.getUserId();
            appendUserId(sb, userId);
            while (userId.equals(oi.getUserId())) {
                IntegrationCheck check = oi.getIntegrationCheck();
                appendIntegrationCheck(sb, check);
                while (check.equals(oi.getIntegrationCheck())) {
                    String changeNum = oi.getChangeNum();
                    appendChangeNum(sb, changeNum);

                    Set<File> files = oi.getFiles();
                    appendFiles(sb, files);

                    if (i.hasNext()) {
                        oi = i.next();
                    } else {
                        // end of set, so get out of here by forcing
                        // termination of all while loops
                        // TODO is there a better way??
                        oi = new OutstandingIntegration(); // NOPMD
                    }
                }
            }
        }

        LOGGER.debug("StringBuilder final length={}", sb.length());
        System.out.println(sb); // NOPMD
    }

    /**
     * Append the user id section to the message.
     * 
     * @param sb
     *            String builder to add to.
     * @param userId
     *            User id to add.
     */
    protected void appendUserId(StringBuilder sb, String userId) {
        sb.append("Userid: ");
        sb.append(userId);
        sb.append("\n");
    }

    /**
     * Append the integration check section to the message.
     * 
     * @param sb
     *            String builder to add to.
     * @param check
     *            Integration check to add.
     */
    protected void appendIntegrationCheck(StringBuilder sb,
            IntegrationCheck check) {
        sb.append(INDENT_1);
        sb.append("Integration Check:");
        sb.append("\n");
        if (check.hasBranchspec()) {
            sb.append(INDENT_2);
            sb.append("Branchspec: ");
            sb.append(check.getBranchspec());
        } else if (check.hasSourceAndTarget()) {
            sb.append(INDENT_2);
            sb.append("Source Codeline: ");
            sb.append(check.getSourceCodeline());
            sb.append("\n");
            sb.append(INDENT_2);
            sb.append("Target Codeline: ");
            sb.append(check.getTargetCodeline());
        } else {
            sb.append(INDENT_2);
            sb.append("(none found)");
        }

        sb.append("\n");
    }

    /**
     * Append the change number section to the message.
     * 
     * @param sb
     *            String builder to add to.
     * @param changeNum
     *            Change number to add.
     */
    protected void appendChangeNum(StringBuilder sb, String changeNum) {
        sb.append(INDENT_2);
        sb.append("Change Number: ");
        sb.append(changeNum);
        sb.append("\n");
    }

    /**
     * Append the files section to the message.
     * 
     * @param sb
     *            String builder to add to.
     * @param files
     *            Files to add.
     */
    protected void appendFiles(StringBuilder sb, Set<File> files) {
        sb.append(INDENT_3);
        sb.append("Files: ");
        sb.append("\n");
        for (File file : files) {
            sb.append(INDENT_4);
            sb.append(file.getName());
            sb.append(", action=");
            sb.append(file.getAction());
            sb.append("\n");
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}
